<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="https://at.alicdn.com/t/font_2790765_pqm82v7ytg.css">
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        img {
            vertical-align: top;
        }

        li {
            list-style: none;
        }

        .wrap {
            width: 1226px;
            margin: 0 auto;
            position: relative;
            overflow: hidden;
        }

        .nav {
            display: flex;
            line-height: 40px;
            text-align: center;
            position: absolute;
            right: 50px;
            bottom: 20px;
            z-index: 9999;
        }

        .nav li {
            width: 10px;
            height: 10px;
            border: 1px solid #333;
            border-radius: 50%;
            margin: 0 5px;
        }

        .active {
            background-color: #6ff;
            color: #fff;
        }

        .swiper {
            overflow: hidden;
            position: relative;
        }

        .swiper .swiper-item {
            float: left;
        }

        .swiper .swiper-item img {
            width: 100%;
        }

        .wrap .prev,
        .wrap .next {
            width: 50px;
            height: 80px;
            text-align: center;
            line-height: 80px;
            background-color: rgba(0, 0, 0, 0.3);
            font-size: 50px;
            color: #fff;
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            z-index: 9999;
            opacity: 0;
            transition: all 0.5s;
        }

        .wrap:hover .prev,
        .wrap:hover .next {
            opacity: 1;
        }

        .wrap .prev {
            left: 10px;
        }

        .wrap .next {
            right: 10px;
        }
    </style>
    <style>
        .mySwiper1 {
            width: 600px;
            margin-top: 50px;
        }

        .mySwiper2 {
            width: 800px;
            margin-top: 50px;
        }

        .mySwiper3 {
            width: 1000px;
            margin-top: 50px;
        }
    </style>
</head>

<body>
    <div class="wrap mySwiper1">
        <i class="prev iconfont icon-left"></i>
        <i class="next iconfont icon-right"></i>
        <!-- 是否需要导航 -->
        <ul class="nav">
            <!-- <li class="active"></li>
            <li></li>
            <li></li>
            <li></li> -->
        </ul>
        <div class="swiper clear">
            <div class="swiper-item"><img src="../images/1.webp" alt=""></div>
            <div class="swiper-item"><img src="../images/2.webp" alt=""></div>
            <!-- <div class="swiper-item"><img src="../images/3.jpg" alt=""></div>
            <div class="swiper-item"><img src="../images/4.webp" alt=""></div>
            <div class="swiper-item"><img src="../images/1.webp" alt=""></div>
            <div class="swiper-item"><img src="../images/2.webp" alt=""></div>
            <div class="swiper-item"><img src="../images/3.jpg" alt=""></div>
            <div class="swiper-item"><img src="../images/4.webp" alt=""></div> -->
            <!-- <div class="swiper-item"><img src="../images/1.webp" alt=""></div> -->
        </div>
    </div>
    <div class="wrap mySwiper2">
        <i class="prev iconfont icon-left"></i>
        <i class="next iconfont icon-right"></i>
        <!-- 是否需要导航 -->
        <ul class="nav">
            <!-- <li class="active"></li>
            <li></li>
            <li></li>
            <li></li> -->
        </ul>
        <div class="swiper clear">
            <div class="swiper-item"><img src="../images/1.webp" alt=""></div>
            <div class="swiper-item"><img src="../images/2.webp" alt=""></div>
            <!-- <div class="swiper-item"><img src="../images/3.jpg" alt=""></div>
            <div class="swiper-item"><img src="../images/4.webp" alt=""></div>
            <div class="swiper-item"><img src="../images/1.webp" alt=""></div>
            <div class="swiper-item"><img src="../images/2.webp" alt=""></div>
            <div class="swiper-item"><img src="../images/3.jpg" alt=""></div>
            <div class="swiper-item"><img src="../images/4.webp" alt=""></div> -->
            <!-- <div class="swiper-item"><img src="../images/1.webp" alt=""></div> -->
        </div>
    </div>
    <div class="wrap mySwiper3">
        <i class="prev iconfont icon-left"></i>
        <i class="next iconfont icon-right"></i>
        <!-- 是否需要导航 -->
        <ul class="nav">
            <!-- <li class="active"></li>
            <li></li>
            <li></li>
            <li></li> -->
        </ul>
        <div class="swiper clear">
            <div class="swiper-item"><img src="../images/1.webp" alt=""></div>
            <div class="swiper-item"><img src="../images/2.webp" alt=""></div>
            <!-- <div class="swiper-item"><img src="../images/3.jpg" alt=""></div>
            <div class="swiper-item"><img src="../images/4.webp" alt=""></div>
            <div class="swiper-item"><img src="../images/1.webp" alt=""></div>
            <div class="swiper-item"><img src="../images/2.webp" alt=""></div>
            <div class="swiper-item"><img src="../images/3.jpg" alt=""></div>
            <div class="swiper-item"><img src="../images/4.webp" alt=""></div> -->
            <!-- <div class="swiper-item"><img src="../images/1.webp" alt=""></div> -->
        </div>
    </div>
</body>
<script>
    // 面向对象  
    // 思想上的提升 ->   就是将你的需求抽象成一个对象,然后针对这个对象分析其特征(属性)与行为(方法)


    // 轮播 = {
    //     点击轮播,
    //     自动轮播,
    //     移入暂停,移出启动,
    //     左右点击切换
    // }

    // 字面量对象 -> 将面向过程中的变量和函数改为对象中的属性和方法

    function swiper(selector) {
        var obj = {
            // 先获取 轮播的容器 -> wrap
            wrap: document.querySelector(selector),
            // 在通过wrap获取其内的子元素
            // nav: swiperObj.wrap.getElementsByClassName("nav")[0],
            // swiper: swiperObj.wrap.getElementsByClassName("swiper")[0],
            // liList: swiperObj.nav.getElementsByTagName("li"),
            // swiperItems: swiperObj.swiper.getElementsByClassName("swiper-item"),
            // prev: swiperObj.wrap.getElementsByClassName("prev")[0],
            // next: swiperObj.wrap.getElementsByClassName("next")[0],
            // swiperWidth: swiperObj.wrap.clientWidth,
            index: 0,
            timer: null,

            // 将获取元素相关的操作整合到一个方法中
            init: function () {
                this.getEle();  //先获取元素
                this.autoComplete();  //先获取元素
                this.bindEvent(); // 绑定事件 
                this.autoPlay(); // 自动轮播
            },
            getEle: function () {
                // this ->  swiperObj
                if (this.wrap) {
                    this.nav = this.wrap.getElementsByClassName("nav")[0];
                    this.swiper = this.wrap.getElementsByClassName("swiper")[0];
                    this.liList = this.nav.getElementsByTagName("li");
                    this.swiperItems = this.swiper.getElementsByClassName("swiper-item");
                    this.prev = this.wrap.getElementsByClassName("prev")[0];
                    this.next = this.wrap.getElementsByClassName("next")[0];
                    this.swiperWidth = this.wrap.clientWidth;
                }
            },
            autoComplete: function () {
                // 动态生成

                // 1. 生成对应图片个数的li放到nav中  
                for (var i = 0; i < this.swiperItems.length; i++) {
                    var li = document.createElement("li");
                    if (i == this.index) { // i==0
                        li.classList.add("active");
                    }
                    this.nav.appendChild(li);
                }

                // 2. swiper中的第一个li 克隆 放到最后面
                var cloneFirst = this.swiper.firstElementChild.cloneNode(true);
                this.swiper.appendChild(cloneFirst);

                // swiper的宽度 =  (n+1) * wrap的宽度   => 四张图片  (4+1)*100%
                // this.swiperItems 传统方法获取元素 -> 自动更新
                this.swiper.style.width = this.swiperItems.length * this.swiperWidth + "px";

                // 单个swiper-item的宽度 = 100 / (n-1) + "%" =>   100 / (4+1) => 20%
                for (var i = 0; i < this.swiperItems.length; i++) {
                    var swiperItem = this.swiperItems[i];
                    swiperItem.style.width = (100 / this.swiperItems.length) + "%";
                }
            },
            // 绑定事件
            bindEvent: function () {
                // this -> swiperObj
                this.click();
                this.hover();
                this.switch();
            },
            click: function () {   // swiperObj.click
                // debugger;
                // this -> swiperObj
                var _this = this;
                for (let i = 0; i < this.liList.length; i++) {  // i=> 0-5
                    let li = this.liList[i];  //获取对应下标的元素
                    li.onclick = function () { // this-> 被点击的li
                        // 点击时记录下标  => 下次从点击位置开始轮播
                        _this.index = i;

                        _this.step();

                    }
                }
            },
            hover: function () {// swiperObj
                // this -> swiperObj
                this.wrap.onmouseenter = () => {
                    clearInterval(this.timer);
                }

                this.wrap.onmouseleave = () => {
                    this.autoPlay();
                }

            },
            switch: function () {

                this.prev.onclick = () => {

                    this.index--;  // 0 1 2 3  

                    this.step();

                }
                this.next.onclick = () => {
                    this.index++;  // 0 1 2 3  
                    // console.log(index);
                    this.step();

                }
            },
            autoPlay: function (delay = 3000) {  // swiperObj.autoPlay()
                // this -> swiperObj
                this.timer = setInterval(() => {
                    this.index++;
                    this.step();

                }, delay)
            },
            step: function () {

                if (this.index < 0) {  // 超出左边的临界值
                    this.index = this.swiperItems.length - 1; // 5-1 => 4  (第五张下标)
                    this.swiper.style.left = -(this.swiperWidth * this.index) + "px";  //切换到第五张

                    this.index--;
                }

                if (this.index > this.swiperItems.length - 1) { // 如果超出第五张 (index > 4) 
                    // 瞬间切换到第一张 
                    this.swiper.style.left = 0;
                    this.index = 0;  //第一张下标   

                    this.index++;  // 下标切到第二张 => 后续会执行animate()  滚动到第二张

                }

                for (var j = 0; j < this.liList.length; j++) {
                    this.liList[j].className = ""; // 清除每一个导航的class名
                }
                var activeIndex = this.index == this.swiperItems.length - 1 ? 0 : this.index;
                this.liList[activeIndex].className = "active";

                this.animate(this.swiper, { left: -(this.swiperWidth * this.index) }, "slow", () => {
                    // 每次滚动结束时 会执行的回调函数
                    // console.log("index", index);

                    // 每次滚动结束时 判断是否滚动到第五张(下标: 4) 
                    if (this.index >= this.swiperItems.length - 1) { // index >= 4 (滚动第五张)
                        this.swiper.style.left = 0;
                        this.index = 0;
                    }

                })
            },
            animate: function (ele, params, type = "normal", callback) {
                // debugger;
                // callback 形参 -> 接收实际参数(本次有点特殊 -> 接收的是一个函数) 


                /* 获取非行内样式 */
                function getStyle(ele, cssKey) {
                    if (window.getComputedStyle) {
                        return window.getComputedStyle(ele)[cssKey];
                    } else {
                        return ele.currentStyle[cssKey];
                    }
                }


                // 记录单属性运动的 cur end speed
                // var cur = ele.offsetLeft;  // 1. 记录小球的起始位置(left)  2. 每次运动后小球的位置
                // var cur = parseFloat(getStyle(ele, cssKey));  // 1. 记录小球的起始位置(left)  2. 每次运动后小球的位置
                // end = parseFloat(end); //去单位 ("1000px" => 1000)
                // var speed = 0;

                var cur = {};   // {left:当前值,top:当前值}
                var end = {};   // {left:终点,top:终点}  单位处理
                var speed = {}  // {left:速度,top:速度}  记录速度

                for (var cssKey in params) {  // csskey => 运动的css属性
                    cur[cssKey] = parseFloat(getStyle(ele, cssKey));
                    end[cssKey] = parseFloat(params[cssKey]);
                    speed[cssKey] = 0;
                }
                // console.log("起始位置", cur);
                // console.log("终点", end);
                // console.log("速度", speed);

                // ele => 运动的元素(元素节点 -> 对象)  -> 元素节点的内置属性(className,id) 和 对象自定义属性
                // var data = {};
                // data.a = 1;
                // data.b = 2;

                // 将计时器的编号 作为元素的属性 存储到元素上(每个运动的元素都有一个timer属性 => 计时器的编号)
                // ele.timer = 1;

                clearInterval(ele.timer);
                ele.timer = setInterval(function () {

                    // 多属性同时运动
                    var isFinished = true;  // 假设都到达终点

                    // {left:"1000px",top:500}
                    for (var cssKey in params) {  // csskey => 运动的css属性  "left"  "top"

                        if (type == "normal") {
                            // 匀速运动
                            if (end[cssKey] > cur[cssKey]) {
                                speed[cssKey] = 20
                            } else if (end[cssKey] < cur[cssKey]) {
                                speed[cssKey] = -20;
                            } else {
                                speed[cssKey] = 0;
                            }

                        } else if (type == "fast") {
                            // 加速运动
                            if (end[cssKey] > cur[cssKey]) {  // 正向运动(0-1000   => speed正值)  
                                speed[cssKey] += 2;
                            } else if (end[cssKey] < cur[cssKey]) { // 反向运动(1000 - 0   => speed负值) 
                                speed[cssKey] -= 2;
                            } else {
                                speed[cssKey] = 0;
                            }

                        } else if (type == "slow") {
                            // 缓冲运动
                            // (终点值 - 当前位置)  => 剩余的距离
                            // 剩余的距离 / 缓冲因子(n) => (每次剩余的n分之1)

                            // 缓冲因子 => 一般在8-12之间

                            if (end[cssKey] > cur[cssKey]) {
                                speed[cssKey] = (end[cssKey] - cur[cssKey]) / 10;  // speed >0 =>  可能会出现 0.00001
                                speed[cssKey] = Math.ceil(speed[cssKey]);  //  如果速度小于1  取  1
                            } else if (end[cssKey] < cur[cssKey]) {
                                speed[cssKey] = (end[cssKey] - cur[cssKey]) / 10;  // speed < 0 =>  可能会出现-0.00001
                                speed[cssKey] = Math.floor(speed[cssKey]);  //  如果速度大于-1  取  -1
                            } else {
                                speed[cssKey] = 0;
                            }

                        }

                        // console.log(speed);
                        cur[cssKey] += speed[cssKey];  // 每次运动后小球的位置
                        ele.style[cssKey] = cur[cssKey] + "px";

                        if (Math.abs(cur[cssKey] - end[cssKey]) <= Math.abs(speed[cssKey])) {  // 到达终点后停下
                            ele.style[cssKey] = end[cssKey] + "px";  // 直接到达终点
                            delete params[cssKey];   //如果当前属性到达终点 => 移出该属性 (不会再遍历该属性)
                            // clearInterval(timer);   // 有一个到达终点就停下  
                        } else {  // 有一个没到达终点   => 推翻假设
                            isFinished = false;
                        }


                    }
                    // console.log(isFinished);
                    if (isFinished) {   ///全都到达终点(本次运动结束)=> 清除计时器
                        clearInterval(ele.timer);
                        if (callback && typeof callback == "function") {  //如果callback有值 且 是函数
                            callback(); //执行该函数  -> 每次运动结束之后执行函数
                        }
                    }

                }, 10);
            }

        }
        obj.init();
        return obj;
    }


    swiper(".mySwiper1");
    swiper(".mySwiper2");
    swiper(".mySwiper3");







</script>

</html>